﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;

namespace PrisonStep
{
    /// <summary>
    /// This class describes our player in the game. 
    /// </summary>
    public class AlienModel
    {
        #region Fields

        public enum States { StanceStart, Stance, Walkstart, Walkloop, WalkLoopStart, Tantrum, Catch, Eat, Ob };

        /// <summary>
        /// Game that uses this player
        /// </summary>
        private PrisonGame mGame;

        //
        // Player location information.  We keep a x/z location (y stays zero)
        // and an orientation (which way we are looking).
        //

        /// <summary>
        /// Player location in the prison. Only x/z are important. y still stay zero
        /// unless we add some flying or jumping behavior later on.
        /// </summary>
        private Vector3 location = new Vector3(0, 0, 0); //new Vector3(275, 0, 1053);

        /// <summary>
        /// The player orientation as a simple angle
        /// </summary>
        private float orientation = 3.14f; // 1.6f;

        /// <summary>
        /// The player transformation matrix. Places the player where they need to be.
        /// </summary>
        private Matrix transform;

        /// <summary>
        /// The rotation rate in radians per second when player is rotating
        /// </summary>
        private float mTurnRate = 2;




        // The section we start in
        private string LastRegion = "R_Section1";


        /// <summary>
        /// Our player model
        /// </summary>
        private AnimatedModel mModel = null;

        /// <summary>
        /// Our players current state
        /// </summary>
        private States mState = States.Stance;


        /// <summary>
        /// This dictionary captures the name and the list of
        /// the triangles for a region.
        /// </summary>
        private Dictionary<string, List<Vector2>> regions = new Dictionary<string, List<Vector2>>();

        private BoundingCylinder mBoundingCyl;
        #endregion

        #region Properties

        public Vector3 VictoriaLocation { get { return location; } }


        public string Region { get { return LastRegion; } }


        public BoundingCylinder BoundingCyl { get { ComputeBoundingCylinder(); return mBoundingCyl; } }

        public States State { get { return mState; } set { mState = value; } }

        public float SlimeWeight { get { return mModel.SlimeWeight; } set { mModel.SlimeWeight = value; } }
        #endregion


        public AlienModel(PrisonGame aGame)
        {
            this.mGame = aGame;
            SetPlayerTransform();

            mModel = new AnimatedModel(aGame, "Alien");
            mModel.AddAssetClip("catcheat", "Alien-catcheat");
            mModel.AddAssetClip("ob", "Alien-ob");
            mModel.AddAssetClip("stance", "Alien-stance");
            mModel.AddAssetClip("tantrum", "Alien-trantrum");
            mModel.AddAssetClip("walkloop", "Alien-walkloop");
            mModel.AddAssetClip("walkstart", "Alien-walkstart");
            mModel.Skinned = true;

            mBoundingCyl = new BoundingCylinder(location, 194, 30);
        }

        /// <summary>
        /// Set the value of transform to match the current location
        /// and orientation.
        /// </summary>
        private void SetPlayerTransform()
        {
            transform = Matrix.CreateRotationY(orientation);
            transform.Translation = location;
        }


        public void LoadContent(ContentManager content)
        {
            mModel.LoadContent(content);
            
            AnimationPlayer lPlayer = mModel.PlayClip("tantrum");
   
        }

        public void Update(GameTime gameTime)
        {
            double lDeltaTotal = gameTime.ElapsedGameTime.TotalSeconds;

            do
            {
                double lDelta = lDeltaTotal;

                Vector3 lInterVect = new Vector3();
                bool lIncomingPie = mGame.Victoria.BazookaProp.PieFire.IncomingPie(BoundingCyl, ref lInterVect);
 
                switch (mState)
                {
                    case States.StanceStart:
                    {
                        if (lIncomingPie)
                        {
                            mModel.PlayClip("catcheat").Speed = 1;
                            mState = States.Catch;

                        }
                        else
                        {
                            location.Y = 0;
                            mModel.PlayClip("stance");
                            mState = States.Stance;
                        }
                        break;
                    }

                    case States.Stance:
                    {
                        mModel.PlayClip("walkstart").Speed = 1;
                        mState = States.Walkstart;

                        break;
                    }
                    case States.Walkstart:
                    {
                        if (mModel.FinishedAnimation())
                        {
                            location.Y = 0;
                            mModel.PlayClip("walkloop");
                            mState = States.WalkLoopStart;
                        }
                        break;
                    }

                    case States.WalkLoopStart:
                    {
                        location.Y = 0;

                        lDelta = 0;
                        mState = States.Walkloop;

                        break;
                    }
                    case States.Walkloop:
                    {
                        if (lIncomingPie)
                        {
                            mModel.PlayClip("catcheat").Speed = 1;
                            mState = States.Catch;
                        }
                        break;
                    }
                    case States.Tantrum:
                    {
                        if (mModel.FinishedAnimation())
                        {
                            mState = States.Walkstart;
                            mModel.PlayClip("walkstart");
                        }
                        break;
                    }
                    case States.Ob:
                    {

                        break;
                    }
                    case States.Catch:
                    {
                        if (mModel.Clip.Time >= 1.0f)
                            mModel.Clip.Speed = 0.0f;

                        if (!lIncomingPie)
                        {
                            mState = States.StanceStart;

                        }
                        break;
                    }

                    case States.Eat:
                    {
                        mModel.Clip.Speed = 1.0f;

                        if (mModel.Clip.Time > 2.0f)
                            mGame.Victoria.BazookaProp.PieFire.AlienPie = null;
                        if (mModel.FinishedAnimation())
                            mState = States.StanceStart;

                        break;
                    }
                }

                mModel.Update(lDelta);

                //
                // Part 1:  Compute a new orientation
                //

                Matrix lDeltaMatrix = mModel.DeltaMatrix;
                float lDeltaAngle = (float)Math.Atan2(lDeltaMatrix.Backward.X, lDeltaMatrix.Backward.Z);
                float lNewOrientation = orientation + lDeltaAngle;


                //
                // Part 2:  Compute a new location
                //

                // We are likely rotated from the angle the model expects to be in
                // Determine that angle.
                Matrix lRootMatrix = mModel.RootMatrix;
                float lActualAngle = (float)Math.Atan2(lRootMatrix.Backward.X, lRootMatrix.Backward.Z);
                Vector3 lNewLocation = location + Vector3.TransformNormal(mModel.mDeltaPosition, Matrix.CreateRotationY(lNewOrientation - lActualAngle));

                orientation = lNewOrientation;
                
                SetPlayerTransform();


                lDeltaTotal -= lDelta;
            }
            while (lDeltaTotal > 0);

        }



        /// <summary>
        /// This function is called to draw the player.
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="gameTime"></param>
        public void Draw(GraphicsDeviceManager graphics, GameTime gameTime)
        {
            Matrix lTransform = Matrix.CreateRotationY(orientation);
            lTransform.Translation = location;
            mModel.Draw(graphics, gameTime, lTransform);

        }


        private void ComputeBoundingCylinder()
        {
            mBoundingCyl.Location = location;
        }

    }
}
